
#include "../include/video.h"
#include "../include/kasm.h"

//#include	"strings.h"

/* Funciones privadas */
#define min(x,y) (x< y ? x : y)
#define dist(x,y) (x< y ? (y)-(x): (x)-(y))
/*
 * Usamos para representar la memoria una matriz de NCOL * NROW
 *
 */
vid * vidmem =(vid *) VIDMEM;

/* Vaiables globales  del video*/
typedef struct
{
	/* Fila  del cursor */
	unsigned int row;
	/* Columna  del cursor */
	unsigned int col;
} coor;
static int copy = 0 ;
static vid * copyvid;
/*es el cursor y su backup*/
static coor cursor = {0 ,0}, cursorbackup = {0 ,0}, mouse = {0, 0}, oldmouse ={0, 0};
/* Backup de coordenadas guardar el video y  recargarlo */
static void
setfmt(int row, int col, char fmt)
{
	/* Setea en (row, col) un formato fmt*/
	vidmem[row * NCOL  + col].formato = fmt;
}


static char
getfmt(int row, int col)
{
	/* retorna el formato */
	return (copyvid[(row * NCOL  + col) ].formato);
}

unsigned int getX(void)
{
return mouse.row;
}

unsigned int getY(void)
{
return mouse.col;
}
/*formato default*/
static char format = WHITE_TXT, formatbackup = WHITE_TXT, formatmouse = GREEN, mouseposoldformat = WHITE_TXT;



static char
getChar(int row, int col)
{
	/*  retiorna el char */
	return (vidmem[(row * NCOL  + col) ].letra);
}

/* hay que modificar esto si se quiere un formato distinto*/
static char
fmtChar(int row, int col)
{
	/* retorna el formato */
	return (vidmem[(row * NCOL  + col) ].formato);
}

static void
setChar(int row, int col, char c, char fmt)
{
	int offset;

	offset = (row * NCOL  + col);

	/* Setea en (row, col) un char c con formato fmt*/
	vidmem[offset].letra = c;
	vidmem[offset].formato = fmt;
}


void clearfmt(){
int row , col, distx , disty, i, j;
	row =  min(oldmouse.row, mouse.row);
	col =  min(oldmouse.col, mouse.col);
	disty = dist(oldmouse.row, mouse.row);
	distx = dist(oldmouse.col, mouse.col);

	for(i =0 ; i < distx  ; i++ )
		for(j =0 ; j < disty ; j++ )
		{
			setfmt(row + j, col + i, getfmt(row + j, col + i));

		}
	

}

void putfmt(){
	int row , col, distx , disty, i, j;
		row =  min(oldmouse.row, mouse.row);
		col =  min(oldmouse.col, mouse.col);
		disty = dist(oldmouse.row, mouse.row);
		distx = dist(oldmouse.col, mouse.col);

		for(i =0 ; i < distx; i++ )
			for(j =0 ; j < disty ; j++ )
			{
				setfmt(row + j, col + i, FMTCOPY);

			}
}

void
saveVideo(vid *videodump)
{
	int i = 0;
	/* guardo el estado al backup*/
	cursorbackup.row = cursor.row;
	cursorbackup.col = cursor.col;
	formatbackup	 = format;

	while (i < NROW * NCOL )
	{
		videodump[i].letra = vidmem[i].letra;
		videodump[i].formato = vidmem[i].formato;
		i++;
	}
}

void
LoadVideo(vid *videodump)
{
	int i = 0;
	/* Restauro estado al backup*/
	cursor.row = cursorbackup.row;
	cursor.col = cursorbackup.col;
	format = formatbackup;

	while (i < NROW * NCOL )
	{
		vidmem[i].letra = videodump[i].letra;
		vidmem[i].formato = videodump[i].formato;
		i++;
	}
}


void initVideoCopy(vid * back){

	setChar(mouse.row, mouse.col, getChar(mouse.row, mouse.col),mouseposoldformat);
	saveVideo(back);
	copy = 1;
	copyvid = back;
	oldmouse.row = mouse.row;
	oldmouse.col = mouse.col;


}

int endVideoCopy(char * st){
	int row , col, distx , disty, i, j, cont = 0;

		row =  min(oldmouse.row, mouse.row);
		col =  min(oldmouse.col, mouse.col);
		disty = dist(oldmouse.row, mouse.row);
		distx = dist(oldmouse.col, mouse.col);

		for(j =0 ; j < disty; j++ )
			for(i =0 ; i < distx; i++ )
			{
				/*
				st[cont] = getchar(row + j, col + i);
				*/
				st[cont] = vidmem[col + i + (NCOL*(row+j))].letra;
				cont++;
				st[cont] = getfmt(row + j, col + i);
				cont++;
			}

	for( i= 0; i< cont; i++)
	
	LoadVideo(copyvid);
	copy = 0;
	clearfmt();
return cont;

}










static char
getbackChar(int row, int col)
{
	/*  retiorna el char */
	return (copyvid[(row * NCOL  + col) ].letra);
}



 void mouseup(void){
int aux;

	if(!copy)
	{
		if (mouse.row != 0)
		{
			aux = mouseposoldformat;
			setfmt(mouse.row, mouse.col, mouseposoldformat);
			mouse.row--;
			mouseposoldformat = fmtChar(mouse.row , mouse.col);

			setfmt(mouse.row, mouse.col, formatmouse);
		}
	}
	else
	{
		if (mouse.row != 0)
		{
			clearfmt();
			mouse.row--;
			putfmt();
		}
	}
}

 void mousedown(void){
int aux;
		if(!copy)
		{
			if (mouse.row != NROW-1)
			{
				aux = mouseposoldformat;
				setfmt(mouse.row, mouse.col ,mouseposoldformat);
				mouse.row++;
				mouseposoldformat = fmtChar(mouse.row , mouse.col);

				setfmt(mouse.row, mouse.col ,formatmouse);
			}
		}
		else
		{
			if (mouse.row !=  NROW)
			{
				clearfmt();
				mouse.row++;
				putfmt();
			}
		}

}

 void mouseleft(void){
int aux;
	if(!copy)
	{
		if (mouse.col != 0)
		{
			aux = mouseposoldformat;
			setfmt(mouse.row, mouse.col, mouseposoldformat);
			mouse.col--;
			mouseposoldformat = fmtChar(mouse.row , mouse.col);

			setfmt(mouse.row, mouse.col,formatmouse);
		}
	}
	else
		if (mouse.col != 0)
		{
			clearfmt();
			mouse.col--;
			putfmt();
		}
}


 void mouseright(void){
int aux;
	if(!copy)
	{
		if (mouse.col != NCOL-1)
		{
			aux = mouseposoldformat;
			setfmt(mouse.row, mouse.col, mouseposoldformat);
			mouse.col++;
			mouseposoldformat = fmtChar(mouse.row , mouse.col);

			setfmt(mouse.row, mouse.col, formatmouse);
		}
	}
	else
		if (mouse.col != NCOL)
		{
			clearfmt();
			mouse.col++;
			putfmt();
		}
}





/* Sube la pantalla una fila*/
static void scrollScreen(void);
/* Limpia pantalla como un clear en linux pero despues hay que setear el cursor en (0,0) */
static void limpiarPantalla(void);







/*Funciones de driver generico*/



static
void
FwdCursor(void)
{
	/*
	 * Si la columna y la fila es la ultima, Scroll.
	 * Si la columna es la ultima pero la fila no, sigue en
	 * la linea de abajo.
	 * Sino, avanza el cursor a la siguiente celda.
	 */

	if (cursor.col +1 == NCOL)
	{


		if (cursor.row +1 ==NROW)
		{
			scrollScreen();
		}
		else
		{
			setCursor(cursor.row+1, 0);
		}
	}
	else
		setCursor(cursor.row, cursor.col+1);
}


void
RwdCursor(void)
{

	if (cursor.col == 0 && cursor.row != 0)
	{
			setCursor(cursor.row-1, NCOL-1);
	}
	else
		if (cursor.col != 0)
		{
			setCursor(cursor.row, cursor.col-1);
		}
}


void
newLineCursor(void)
{
	/* Si estoy en la ultima fila, hago scroll, antes borrando el cursor */
	if (cursor.row == NROW-1)
	{
		setChar(cursor.row, cursor.col, 0, format);
		scrollScreen();
	}
	else
	/* Sino, pongo el cursor en la fila siguiente, columna 0 */
{
/*
	pinto la linea donde estoy

*/	
		setChar(cursor.row, cursor.col, ' ', format);
		while(cursor.col < NCOL)
		{
		setfmt(cursor.row, cursor.col, format);
		cursor.col++;	
		}
		setCursor(cursor.row+1, 0);
}
}

void
initVideo(void)
{
	/* Limpiamos la  pantalla y ubicamos al cursor en (NROW -1 ,0) */
	limpiarPantalla();
	setCursor(NROW -1 , 0);
};




void
setCursor(int row, int col)
{
	/* Borra el lugar donde estaba el cursor y lo pone en otro lado */
	setChar(cursor.row, cursor.col, 0, format);

	cursor.row = row;
	cursor.col = col;

	setChar(cursor.row, cursor.col, '|', WHITE_BLINK_TEXT);


}



static void
scrollScreen(void)
{
	int row, col;
	_Cli();

	setfmt(mouse.row, mouse.col, mouseposoldformat);
	

/*
	pinto la linea donde estoy

*/	
		setChar(cursor.row, cursor.col, ' ', format);
		while(cursor.col < NCOL)
		{
		setfmt(cursor.row, cursor.col, format);
		cursor.col++;	
		}
		setCursor(cursor.row+1, 0);

	/*Subo la pantalla una fila */
	for (row = 0; row < NROW - 1; ++row)
		for (col = 0; col < NCOL; ++col)
			setChar(row, col, getChar(row+1, col), fmtChar(row+1, col));
	setCursor(NROW - 1 , 0);
	
	/* Limpio ultima fila  y pongo el cursor */
	for (col = 0; col < NCOL; ++col)
		setChar(NROW - 1 , col, 0, format);
	setCursor(NROW - 1 , 0);
	mouseposoldformat = fmtChar(mouse.row, mouse.col);

	setfmt(mouse.row, mouse.col, formatmouse);
	_Sti();
}

void
putVideoChar(char c)
{
	int row, col;

	row = cursor.row;
	col = cursor.col;

	/* Escribo un caracter donde esta el cursor */
	FwdCursor();
	if (row +1 == NROW && col +1 == NCOL)
		setChar(NROW - 2, NCOL -1, c, format);
	else
		setChar(row, col, c, format);
}
void
setDefaultFormat(int c)
{
	format = c;
}


int getDefaultFormat(void)
{
	return format;
}




/*Funcion no generica,  dependen de la arquitectura.*/

static
void
limpiarPantalla(void)
{
	unsigned int i = 0;

	/* Limpa la poniendo fondo negro en la pantalla y letra blanca */
	while (i < NROW * NCOL)
	{
		vidmem[i].letra = '\0';
		vidmem[i].formato = format;
		i++;
	}
}


void clearScreen(void)
{
	limpiarPantalla();
	setCursor(0, 0);
}









